package lab2;


import java.util.AbstractSet;
import java.util.Iterator;
import java.util.NoSuchElementException;



/**
 * Class ClosedHashSet represents Set
 * * Implemented add, contains, remove, size, isEmpty, toString, clear and iterator
 * @author Aleksey Singaevskiy
 */
public class ClosedHashSet extends AbstractSet<Integer> {

	private int size = 0;
	private int capacity = 0;
	private Integer values[];
	private int flags[]; // 0 В— EMPTY, 1 В— DELETED, 2 В— USED

	/**
	 * @param capacity is size of Set
	 */
	public ClosedHashSet(int capacity) {
		if (capacity < 0)
			throw new IllegalArgumentException("Invalid argument");
		this.capacity = capacity;
		values = new Integer[capacity];
		flags = new int[capacity];
	}
	
	/**
	 * @param is value to generate the hashkey
	 * @return hashkey
	 */
	private int hashkey(int value) {
		return ((value >> 11) ^ value) % capacity;
	}
		
	/**
	 * @param value to add in set
	 * @return true if add was successful
	 */
	public boolean add(Integer value) {
		if (size == capacity)
			throw new ArrayIndexOutOfBoundsException();
		if (value == null)
			throw new IllegalArgumentException("Argument can't be null");
		int index = hashkey(value);
		while (flags[index] > 1) {
			index = (index + 1) % capacity;
		}
		values[index] = value;
		flags[index] = 2;
		size++;
		return true;
	}
	
	/**
	 * @param value to remove
	 * @return true if remove was successful and false if element does not contains in set
	 */
	public boolean remove(int value) {
		int index = hashkey(value);
		int step = 0;
		while (true) {
			if (flags[index] == 0 || step == capacity)
				return false;
			if (flags[index] == 2 && values[index] == value) {
				flags[index] = 1;
				values[index] = null;
				size--;
				return true;
			}
			step++;
			index = (index + 1) % capacity;
		}
	}
	
	/**
     * @param value the element to search in set
     * @return false if value not contains and true if value contains
     */
	public boolean contains(int value) {
		int index = hashkey(value);
		int step = 0;
		while (true) {
			if (flags[index] == 0 || step == capacity)
				return false;
			if (flags[index] == 2 && values[index] == value) {
				return true;
			}
			index = (index + 1) % capacity;
			step++;
		}
	}	
	
	/**
	 * Iterator for CHS
	 */
	class CHSIterator implements Iterator<Integer> {
		private int cur = 0;
		
		 /**
         * @return next element
         */
		@Override
		public Integer next() {
			if (hasNext()) {
				for (int i = cur; i < capacity; i++) {
					if (values[cur] != null)
						break;
					cur = i;
				}
				return values[cur++];
			} else
				throw new NoSuchElementException("There's no elements anymore!");
		}
		
		/**
         * @return true if current position of iterator has next value; false otherwise.
         */
				@Override
		public boolean hasNext() {
			for (int i = cur; i < capacity; i++) {
				if (values[i] != null)
					return true;				
			}
			return false;
		}
		
		/**
         * @param pos is starting position
         */
		public CHSIterator(int pos) {
			cur = pos;
		}
		
		/**
         * Unsupported method
         */
				@Override
		public void remove() {
			throw new UnsupportedOperationException("Operation is not supported");
		}
	}
	
	/**
	 * @return size of CHS
	 */
	@Override
	public int size() {
		return this.size;
	}

	/**
     * clear CHS
     */	
	public void clear() {
		for (int i = 0; i < capacity; i++) {
			flags[i] = 0;
			values[i] = null;
		}
		size = 0;
	}
	/**
	 * overrided iterator
	 * @return iterator with pos == 0	
	 */
	@Override
	public CHSIterator iterator() {
		return new CHSIterator(0);
	}

}
